以下内容完全来源于 RednaxelaFX 两篇文章的总结:
面向对象语言中经常会对函数调用的第一个参数做特殊处理,包括语法和语义都很特别。
- 语法的特别之处在于实际上的第一个参数不用写在参数列表里,而是写在某种特殊符号之前(b.foo(0)的“.”),也就是所谓的隐含参数。
- 语义的特别之处在于这第一个参数的称为方法调用的接收者(reciever),它的实际类型会参与到方法分派的判断中,而其余的参数要么只参与静态类型判断(单一分派+方法重载),要么也以实际类型参与到方法分派的判断(多分派)。
在单一分派静态类型的面向对象语言中,重载仍然是编译时概念:编译器只会根据静态变量的类型来判断选择哪个版本的重载,而不像运行时多态那样根据值的实际类型来判断。
在C#4.0之前方法都是单一分派的,C#4.0增加了“动态类型”,因为dynamic类型运行时才能确定类型,所以会参与方法分派。也就是说,如果一个虚方法调用的参数的类型是都是dynamic(如果有静态类型参数,那么静态类型参数将不参与方法分派,而是在编译期参与方法推断:This means that for all arguments not statically typed dynamic, the compile time types will be used, regardless of their runtime types.),那么整个方法调用都无法在编译时判定到底应该选用哪个具体版本。CLR会根据方法接收者(this)和每个参数的实际类型来进行方法分派,这个语义与多分派的语义是相同的。如下代码所示:
1 | using System; |